{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# SymPy Tutorial"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "SymForce is built on the [SymPy](https://sympy.org) API for symbolic algebra. If you're not familiar with SymPy or symbolic computation, go through [their](https://docs.sympy.org/latest/tutorial/index.html) tutorial.\n",
    "Some basic usage is shown here."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "First, some optional configuration - see [Symbolic APIs](#Symbolic-APIs) below for more information:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import symforce\n",
    "\n",
    "symforce.set_symbolic_api(\"symengine\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Some imports that are useful for notebooks - you'll see these across many of our tutorials:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from symforce.notebook_util import display\n",
    "from symforce.notebook_util import print_expression_tree\n",
    "from symforce.notebook_util import set_notebook_defaults\n",
    "\n",
    "set_notebook_defaults()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Always import the SymPy API through SymForce, because symforce can switch out the symbolic implementation of the API and adds a few minor but important augmentations.  [symforce.symbolic](../api/symforce.symbolic.html) includes both the supported parts of the underlying symbolic API, as well as all of the types from [symforce.geo](../api/symforce.geo.html) and [symforce.cam](../api/symforce.cam.html).  Let's define some algebraic symbols:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import symforce.symbolic as sf\n",
    "\n",
    "x = sf.Symbol(\"x\")\n",
    "y = sf.Symbol(\"y\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Build a symbolic expression:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "expr = x**2 + sf.sin(y) / x**2\n",
    "display(expr)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This expression object is a tree of operations and arguments:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print_expression_tree(expr)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can evaluate this numerically by plugging in values:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "display(expr.subs({x: 1.2, y: 0.4}))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can perform symbolic manipulation like differentiation, integration, simplifiation, etc.."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "display(expr.diff(y))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "display(sf.series(expr, y))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Symbolic APIs"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "SymForce supports two underling symbolic APIs.  The [SymPy](https://sympy.org) API is pure Python, and the [SymEngine](https://symengine.org) API is a C++ implementation of much of SymPy.  SymEngine is the default, and if you installed SymForce with `pip` or built it from source you'll have it already.  SymEngine is much faster than SymPy by a factor of 100 or more.  However, SymEngine doesn't implement everything SymPy does.  SymForce abstracts over some of these differences, and adds support for some operations by converting between SymEngine and SymPy calls.\n",
    "\n",
    "For how to set the symbolic api, see the docs for [symforce.set_symbolic_api](../api/symforce.html#symforce.set_symbolic_api)."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
